#include "../lib_include/Acceptor.h"
#include "../lib_include/Logger.h"
#include "../lib_include/EventLoop.h"
#include "../lib_include/InetAddress.h"
#include "../lib_include/SocketsOps.h"

#include <errno.h>
#include <fcntl.h>
#include <unistd.h>

using namespace netlib;
using namespace netlib::net;

Acceptor::Acceptor(EventLoop* loop, const InetAddress& listenAddr, bool reuseport)
  : loop_(loop),
    acceptSocket_(sockets::createNonblockingOrDie(listenAddr.family())),
    acceptChannel_(loop, acceptSocket_.fd()),
    listening_(false),
    idleFd_(::open("/dev/null", O_RDONLY | O_CLOEXEC)) // 打开一个空闲描述符
{
    assert(idleFd_ >= 0);
    acceptSocket_.setReuseAddr(true);
    acceptSocket_.setReusePort(reuseport);
    acceptSocket_.bindAddress(listenAddr);
    acceptChannel_.setReadCallback(std::bind(&Acceptor::handleRead, this));
}

Acceptor::~Acceptor()
{
    acceptChannel_.disableAll();
    acceptChannel_.remove();
    ::close(idleFd_);
}

void Acceptor::listen() // 套接字开启监听
{
    loop_->assertInLoopThread();
    listening_ = true; // 修改监听状态
    acceptSocket_.listen();
    acceptChannel_.enableReading(); // 向事件表注册可读事件
}

void Acceptor::handleRead() // 有新连接到来的处理函数，调用accept
{
    loop_->assertInLoopThread();
    InetAddress peerAddr; // 
    int connfd = acceptSocket_.accept(&peerAddr);
    if (connfd >= 0) // 成功接收一个新连接
    {
        if (newConnectionCallback_) // 建立新连接的回调函数，如果没有设置则关闭连接
            newConnectionCallback_(connfd, peerAddr);
        else
            sockets::close(connfd);
    }
    else // 接受连接失败
    {
        LOG_SYSERR << "in Acceptor::handleRead";

        // 如果是EMFILE代表描述符已用尽，如果不接受连接，会一直触发可读事件
        // 所以接受又马上关闭连接，处理掉这个可读事件
        if (errno == EMFILE)
        {
            ::close(idleFd_);
            idleFd_ = ::accept(acceptSocket_.fd(), NULL, NULL);
            ::close(idleFd_);
            idleFd_ = ::open("/dev/null", O_RDONLY | O_CLOEXEC);
        }
    }
}